﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using Microsoft.Win32;
using System.Windows;
using System.Xml;
using WinForm = System.Windows.Forms;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.Widgets;
using SHomeWorkshop.LunarConcept.ModifingManager;
using SHomeWorkshop.LunarConcept.Controls;
using System.Windows.Media;
using SHomeWorkshop.LunarConcept.Widgets.Interfaces;

namespace SHomeWorkshop.LunarConcept.Commands
{
    /// <summary>
    /// 创建时间：2011年12月28日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：格式化为标题命令。
    /// ★★说明：关于自定义命令的实现，可参考“NewDocument”类的备注。
    /// </summary>
    public static class FormatTitleCommand
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// ★②，修改静态构造方法名。
        /// </summary>
        static FormatTitleCommand()//类型构造器
        {
            //★③，修改两个字符串参数名。★④以及第三个参数的类型名。
            routedUICmd = new RoutedUICommand(
                "FormatTitleCommand",
                "FormatTitleCommand",
                typeof(FormatTitleCommand),//创建RoutedUICommand对象
                null);

            //如果需要挂接快捷键，请参考下面这段代码：
            //routedUICmd = new RoutedUICommand(
            //    "SaveDocumentCommand",
            //    "SaveDocumentCommand",
            //    typeof(SaveDocumentCommand),//创建RoutedUICommand对象
            //    new InputGestureCollection() 
            //    { 
            //        //★⑤，修改此处三个参数，以便挂接快捷键。
            //        new KeyGesture(Key.S,ModifierKeys.Control,"Ctrl+S")
            //    });

            cmdBinding.Command = routedUICmd;
            cmdBinding.CanExecute += new CanExecuteRoutedEventHandler(cmdBinding_CanExecute);
            cmdBinding.Executed += new ExecutedRoutedEventHandler(cmdBinding_Executed);
        }

        #endregion

        #region 字段与属性===================================================================================================

        private static CommandBinding cmdBinding = new CommandBinding();
        /// <summary>
        /// 用在主窗口CommandBindings集合中的命令绑定。
        /// 
        /// 它的Command是RoutedUICommand。
        /// ——因此，RoutedUICommand是否可以运行将由CmdBinding的CanExecute事件决定。
        /// ——而且，RoutedUICommand的执行也是通过CmdBinding的Execute事件来进行的。
        /// </summary>
        public static CommandBinding CmdBinding
        {
            get { return cmdBinding; }
        }

        private static RoutedUICommand routedUICmd;
        /// <summary>
        /// [只读静态属性]表示在WPF系统中注册的一个RoutedUICommand。
        /// ——必须和CommandBinding配合才能使用。
        ///     CommandBinding要添加到主窗口的CommandBindings集合中；
        ///     RoutedUICommand则要向WPF系统注册。
        ///     
        /// ★说明：使用静态属性是因为这样在Xaml代码中比较便于绑定。
        /// </summary>
        public static RoutedUICommand RoutedUICmd
        {
            get { return routedUICmd; }
        }

        #endregion

        #region 方法=========================================================================================================

        static void cmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            //★⑧，修改此方法的实现。
            e.CanExecute = true;
        }

        static void cmdBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            //★⑦，修改此方法的实现。

            //Execute();//此命令不绑定。
        }

        /// <summary>
        /// [公开静态方法]即使此命令处于禁用状态，也可以通过代码调用此方法来执行特定任务！！！
        /// 
        /// 当被绑定的命令被调用（触发）时，会引发cmdBinding_Executed事件。
        /// 在cmdBinding_Executed事件处理器方法中已添加了调用Execute()方法的代码。
        /// 
        /// ——因此，触发命令，就相当于调用此方法！！！
        /// </summary>
        public static void Execute()
        {
            string result = FormatTitle();
            if (result != string.Empty)
            {
                MessageBox.Show("　　格式化标题操作出现异常。异常信息如下：\r\n　　" + result,
                    Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
        }

        /// <summary>
        /// 格式化文本为某级标题。
        /// </summary>
        /// <param name="titleStyle">标题等级。</param>
        /// <param name="upLevel">默认为null，忽略此参数。为true时在原有层级上加大一级。为false时减小一级。此值不为null时，会忽略第一个参数指定的标题层级。</param>
        /// <returns></returns>
        public static string FormatTitle(Enums.TitleStyle titleStyle = Enums.TitleStyle.Normal, bool? upLevel = null)
        {
            if (Globals.MainWindow == null) return "　　未找到主窗口。";

            LunarConcept.Controls.EditorManager manager = Globals.MainWindow.EditorManager;
            if (manager == null) return "　　未找到主窗口的页面管理器。";
            try
            {
                List<Widgets.Widget> selectedWidgets = manager.GetSelectedWidgetsList();

                if (selectedWidgets.Count <= 0) return "　　未选定部件。";

                var activeWidget = manager.GetMainSelectedWidget();
                if (upLevel != null && upLevel.HasValue)
                {
                    //字号变小，标题层级变大
                    if (upLevel.Value == true)
                    {
                        if (activeWidget.TitleLevel < Enums.TitleStyle.Normal)
                            titleStyle = activeWidget.TitleLevel + 1;
                        else return string.Empty;
                    }
                    else if (upLevel.Value == false)
                    {
                        if (activeWidget.TitleLevel > Enums.TitleStyle.MainTitle)
                            titleStyle = activeWidget.TitleLevel - 1;
                        else return string.Empty;
                    }
                }

                double newFontSize = TitleManager.GetFontSize(titleStyle);
                string newFontName = TitleManager.GetFontName(titleStyle);
                FontWeight newFontWeight = TitleManager.GetFontWeight(titleStyle);

                //if (newFontSize < 12 || newFontSize > 96) return "　　字号必须在[12，96]区间之中。";
                //标题会按层级加大字号，这行添加上去可能出错。

                string description = string.Format("部件格式化为 {0} 级标题", titleStyle.ToString());
                ModifingInfo info = new ModifingInfo() { ModifingDescription = description };
                manager.GetSelectedPageEditorStatus(info);
                manager.GetSelectedWidgetStatus_Old(info);
                manager.GetSelectedWidgetStatus_New(info);

                ModifingItem<Action, ModifingInfo> mi = new ModifingItem<Action, ModifingInfo>(info);

                XmlDocument tmpDoc = new XmlDocument();

                //被挂接的线（不一定会有成员）。
                List<ILinkableLine> linkedLines = new List<ILinkableLine>();

                foreach (Widgets.Widget w in selectedWidgets)
                {
                    if (w.MasterEditor == null) return "　　未找到某部件所属的页面编辑器。无法继续。";

                    Action actTitleLevel = new Action(w.MasterEditor.Id, w.Id, w.GetType().Name,
                        XmlTags.TitleLevelTag, w.TitleLevel.ToString(), titleStyle.ToString());
                    w.TitleLevel = titleStyle;
                    mi.AddAction(actTitleLevel);

                    if (titleStyle == Enums.TitleStyle.Normal)
                    {
                        //格式化为正文时，需要将字号统一改为默认字号？？？
                        //——这样不能保留此前的信息。例如：上下标，无法恢复。

                        //去除可能存在的字号信息，保存可能存在的上下标Xml特性。
                        Commands.TextCommands._TCSetWidgetsFontSize.ReplaceAttribute(null, mi, w);

                        //去除加粗
                        Commands.TextCommands._TCSetWidgetsBold.ReplaceAttribute(null, mi, w);

                        //去除字体名
                        Commands.TextCommands._TCSetWidgetsFontFamily.ReplaceAttribute(null, mi, w);
                    }

                    //对于实现了ICanBeLinkedWidget接口的各部件来说，
                    //只有ContentWidget字型、字号、加粗、倾斜等发生改变时才需要保持中心点。
                    //矩形、菱形、椭圆不会因文本变化而改变部件体积。
                    ContentWidget cw = w as ContentWidget;
                    if (cw == null)
                    {
                        //ReplaceFontSizeAttribute(newFontSize, mi, w);
                        //ReplaceFontNameAttribute(newFontName, mi, w);
                        //ReplaceFontWeightAttribute(newFontWeight, mi, w);
                        //w.Build();//这三个方法为避免重复Build已经取消了这行代码。
                        //2012年6月24日，Widget类已经支持TitleLevel，如果是标题，直接会按指定字号、字形来显示。
                        //因此，可以保留这些文本片段字形、字号信息。


                        #region 矩形在作标题时，需要处理缩进等位置属性。2012年6月25日取消。
                        //Widgets.RectangleWidget rw = w as Widgets.RectangleWidget;
                        //if (rw != null)
                        //{
                        //FormatRectangleTitle(titleStyle, manager, mi, rw);
                        //2012年6月25日晚，改为只处理一下底边。

                        //又，既然矩形一般已经不用作标题，也决定不支持自动编号与大纲，那么就没有必要再更改“自动折行”了。
                        //自然，自动调整底边也是没有必要的。2012年7月17日悉数取消之。

                        //if (rw.FixTextWidth == false)
                        //{
                        //    Action actFixTextWidth = new Action(rw.MasterEditor.Id, rw.Id, rw.GetType().Name,
                        //        XmlTags.FixTextWidthTag, false.ToString(), true.ToString());
                        //    rw.FixTextWidth = true;
                        //    mi.AddAction(actFixTextWidth);
                        //}

                        //RectangleWidget.ResetRectangleWidgetHeight(mi, rw);
                        //}
                        #endregion
                    }
                    else
                    {
                        #region 文本块在作标题时，进行自动缩进。
                        TextArea tw = w as Widgets.TextArea;
                        if (tw != null)
                        {
                            FormatTextAreaTitle(titleStyle, manager, mi, tw);
                        }
                        #endregion

                        if (cw.IsLinked)
                        {
                            #region 取出所有挂接的线（不管被挂接的线是否两个端点均挂接都算）

                            foreach (UIElement uePage in manager.Children)
                            {
                                PageEditor pe = uePage as PageEditor;
                                if (pe == null) continue;

                                foreach (UIElement ue in pe.Children)
                                {
                                    ILinkableLine linkedLine = ue as ILinkableLine;
                                    if (linkedLine == null) continue;

                                    if (linkedLine.StartMasterId == w.Id || linkedLine.EndMasterId == w.Id)
                                    {
                                        if (linkedLines.Contains(linkedLine) == false)
                                        {
                                            linkedLines.Add(linkedLine);
                                        }
                                    }
                                }
                            }

                            #endregion

                            Point oldTopLeft = cw.TopLeft;
                            Point oldBottomRight = cw.BottomRight;//备用

                            //ReplaceFontSizeAttribute(newFontSize, mi, w);
                            //ReplaceFontNameAttribute(newFontName, mi, w);
                            //ReplaceFontWeightAttribute(newFontWeight, mi, w);
                            //w.Build();

                            //保持中心点
                            Point oldCenter = new Point(oldTopLeft.X + (oldBottomRight.X - oldTopLeft.X) / 2,
                                oldTopLeft.Y + (oldBottomRight.Y - oldTopLeft.Y) / 2);
                            cw.InvalidateArrange(); cw.UpdateLayout();

                            Point newTopLeft = cw.TopLeft;
                            Point newBottomRight = cw.BottomRight;
                            Point newLocation = new Point(oldCenter.X - (newBottomRight.X - newTopLeft.X) / 2,
                                oldCenter.Y - (newBottomRight.Y - newTopLeft.Y) / 2);

                            Action actNewLocation = new Action(cw.MasterEditor.Id, cw.Id, cw.GetType().Name, XmlTags.LocationTag,
                                cw.Location.ToString(), newLocation.ToString());
                            cw.Location = newLocation;
                            mi.AddAction(actNewLocation);
                        }
                        //else
                        //{
                        //ReplaceFontSizeAttribute(newFontSize, mi, w);
                        //ReplaceFontNameAttribute(newFontName, mi, w);
                        //ReplaceFontWeightAttribute(newFontWeight, mi, w);
                        //w.Build();
                        //}
                    }
                }

                #region
                if (linkedLines.Count > 0)
                {
                    foreach (ILinkableLine linkedLine in linkedLines)
                    {
                        Widget startMaster = linkedLine.MasterEditor.GetWidget(linkedLine.StartMasterId);
                        Widget endMaster = linkedLine.MasterEditor.GetWidget(linkedLine.EndMasterId);
                        if (startMaster == null || endMaster == null) continue;//如果有一个已经被删除，则不进行位移。

                        Rect rectStart = new Rect(startMaster.TopLeft, startMaster.BottomRight);
                        rectStart.X -= 4; rectStart.Y -= 4; rectStart.Width += 8; rectStart.Height += 8;
                        Rect rectEnd = new Rect(endMaster.TopLeft, endMaster.BottomRight);
                        rectEnd.X -= 4; rectEnd.Y -= 4; rectEnd.Width += 8; rectEnd.Height += 8;

                        Point startCenter = new Point(rectStart.Left + (rectStart.Width / 2), rectStart.Top + (rectStart.Height / 2));
                        Point endCenter = new Point(rectEnd.Left + (rectEnd.Width / 2), rectEnd.Top + (rectEnd.Height / 2));

                        PointToRect.ArrowPoints aptStart = PointToRect.GetCrossPointToRect(rectStart, endCenter);
                        PointToRect.ArrowPoints aptEnd = PointToRect.GetCrossPointToRect(rectEnd, startCenter);

                        Action actStart = new Action(linkedLine.MasterEditor.Id, linkedLine.Id, linkedLine.GetType().Name, XmlTags.StartPointTag,
                            linkedLine.StartPoint.ToString(), aptStart.Top.ToString());
                        linkedLine.StartPoint = aptStart.Top;

                        Action actEnd = new Action(linkedLine.MasterEditor.Id, linkedLine.Id, linkedLine.GetType().Name, XmlTags.EndPointTag,
                            linkedLine.EndPoint.ToString(), aptEnd.Top.ToString());
                        linkedLine.EndPoint = aptEnd.Top;

                        mi.AddAction(actStart);
                        mi.AddAction(actEnd);
                    }
                }
                #endregion

                manager.RegisterModifingItem(mi);
                manager.RefreshAutoNumberStrings();//刷新自动编号。自动编号不需要写入后台xml文档。
                return string.Empty;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        //private static void FormatRectangleTitle(Enums.TitleStyle titleStyle, LunarConcept.Controls.EditorManager manager, ModifingItem<Action, ModifingInfo> mi, Widgets.RectangleWidget rw)
        //{
        //    //在此处决定标题的两个定位点的横坐标(纵坐标不动，
        //    //底部纵坐标则由ResetRectangleWidgetHeight()方法决定）。

        //    WidgetStyle defStyleOfDoc = manager.GetDefaultWidgetStyle(typeof(Widgets.RectangleWidget).Name);
        //    Point? newStartPoint = TitleManager.GetTitleStartPoint(rw.MasterEditor.MasterManager,
        //        rw.MasterEditor, rw.StartPoint, titleStyle);
        //    if (newStartPoint != null && newStartPoint.HasValue)
        //    {
        //        Action actStartPt = new Action(rw.MasterEditor.Id, rw.Id, rw.GetType().Name, XmlTags.StartPointTag,
        //                        rw.StartPoint.ToString(), newStartPoint.Value.ToString());
        //        rw.StartPoint = newStartPoint.Value;
        //        mi.AddAction(actStartPt);
        //    }

        //    Point? newEndPoint = TitleManager.GetTitleEndPoint(rw.MasterEditor.MasterManager,
        //        rw.MasterEditor, rw.EndPoint, titleStyle);
        //    if (newEndPoint != null && newEndPoint.HasValue)
        //    {
        //        Action actEndPt = new Action(rw.MasterEditor.Id, rw.Id, rw.GetType().Name, XmlTags.EndPointTag,
        //                        rw.EndPoint.ToString(), newEndPoint.Value.ToString());
        //        rw.EndPoint = newEndPoint.Value;
        //        mi.AddAction(actEndPt);
        //    }

        //    if (rw.WidgetForeColor != defStyleOfDoc.WidgetForeColor)
        //    {
        //        Action actForeColor = new Action(rw.MasterEditor.Id, rw.Id, rw.GetType().Name, XmlTags.WidgetForeColor,
        //            BrushManager.GetName(rw.WidgetForeColor), BrushManager.GetName(defStyleOfDoc.WidgetForeColor));
        //        rw.WidgetForeColor = defStyleOfDoc.WidgetForeColor;
        //        mi.AddAction(actForeColor);
        //    }

        //    if (rw.WidgetBackColor != Brushes.Transparent)
        //    {
        //        Action actBackColor = new Action(rw.MasterEditor.Id, rw.Id, rw.GetType().Name, XmlTags.WidgetBackColor,
        //            BrushManager.GetName(rw.WidgetBackColor), BrushManager.GetName(Brushes.Transparent));
        //        rw.WidgetBackColor = Brushes.Transparent;
        //        mi.AddAction(actBackColor);
        //    }

        //    //rw.LineDash = LineDashType.DashType.Dash;//线型也不变，防止用户有特殊需求。

        //    if (rw.WidgetLineWidth != 1)
        //    {
        //        Action actLineWidth = new Action(rw.MasterEditor.Id, rw.Id, rw.GetType().Name, XmlTags.WidgetLineWidthTag,
        //            rw.WidgetLineWidth.ToString(), "1");
        //        //rw.WidgetLineWidth = 1;
        //        mi.AddAction(actLineWidth);
        //    }

        //    //rw.WidgetLineColor = Brushes.Crimson;//边框色不变，防止用户有特殊需求。

        //    if (rw.FixTextWidth == false)
        //    {
        //        Action actFixTextWidth = new Action(rw.MasterEditor.Id, rw.Id, rw.GetType().Name, XmlTags.FixTextWidthTag,
        //            rw.FixTextWidth.ToString(), true.ToString());
        //        rw.FixTextWidth = true;
        //        mi.AddAction(actFixTextWidth);
        //    }

        //    //ReplaceFontSizeAttribute(newFontSize, mi, w);
        //    //ReplaceFontNameAttribute(newFontName, mi, w);
        //    //ReplaceFontWeightAttribute(newFontWeight, mi, w);
        //    //w.Build();
        //    //2012年6月24日，Widget类支持TitleLevel，已无必要去除这些字形、字号信息。
        //    //Widget类会根据TitleLevel自行决定如何呈现文本。

        //    Widgets.RectangleWidget.ResetRectangleWidgetHeight(mi, rw);
        //}

        private static void FormatTextAreaTitle(Enums.TitleStyle titleStyle, LunarConcept.Controls.EditorManager manager, ModifingItem<Action, ModifingInfo> mi, Widgets.TextArea tw)
        {
            //在此处决定标题的两个定位点的横坐标(纵坐标不动，
            //底部纵坐标则由ResetRectangleWidgetHeight()方法决定）。

            WidgetStyle defStyleOfDoc = manager.GetDefaultWidgetStyle(typeof(Widgets.TextArea).Name);

            if (tw.TitleLevel != Enums.TitleStyle.Normal)//正文（Normal），需要能够出现在任意标题层级的下一级位置，因此不改其缩进。
            {
                Point? newStartPoint = TitleManager.GetTitleStartPoint(tw.MasterEditor.MasterManager,
                    tw.MasterEditor, tw.StartPoint, titleStyle);
                if (newStartPoint != null && newStartPoint.HasValue)
                {
                    Action actStartPt = new Action(tw.MasterEditor.Id, tw.Id, tw.GetType().Name, XmlTags.StartPointTag,
                                    tw.StartPoint.ToString(), newStartPoint.Value.ToString());
                    tw.StartPoint = newStartPoint.Value;
                    mi.AddAction(actStartPt);
                }
            }

            if (tw.WidgetForeColor != defStyleOfDoc.WidgetForeColor)
            {
                Action actForeColor = new Action(tw.MasterEditor.Id, tw.Id, tw.GetType().Name, XmlTags.WidgetForeColor,
                    BrushManager.GetName(tw.WidgetForeColor), BrushManager.GetName(defStyleOfDoc.WidgetForeColor));
                tw.WidgetForeColor = defStyleOfDoc.WidgetForeColor;
                mi.AddAction(actForeColor);
            }

            if (tw.WidgetBackColor != Brushes.Transparent)
            {
                Action actBackColor = new Action(tw.MasterEditor.Id, tw.Id, tw.GetType().Name, XmlTags.WidgetBackColor,
                    BrushManager.GetName(tw.WidgetBackColor), BrushManager.GetName(Brushes.Transparent));
                tw.WidgetBackColor = Brushes.Transparent;
                mi.AddAction(actBackColor);
            }

            if (tw.WidgetLineWidth != 1)
            {
                Action actLineWidth = new Action(tw.MasterEditor.Id, tw.Id, tw.GetType().Name, XmlTags.WidgetLineWidthTag,
                    tw.WidgetLineWidth.ToString(), "1");
                //tw.WidgetLineWidth = 1;
                mi.AddAction(actLineWidth);
            }
        }

        //private static void ReplaceFontSizeAttribute(double newFontSize, ModifingItem<Action, ModifingInfo> mi, Widgets.Widget w)
        //{
        //    XmlNode paragraphSetNode = w.ParagraphSetNode;
        //    string oldXml = paragraphSetNode.InnerXml;

        //    //<ParagraphSet <Paragraph <Text 

        //    XmlNodeList paragraphNodes = paragraphSetNode.SelectNodes(XmlTags.ParagraphTag);
        //    foreach (XmlNode paragraphNode in paragraphNodes)
        //    {
        //        XmlNodeList textNodes = paragraphNode.SelectNodes(XmlTags.TextTag);
        //        foreach (XmlNode textNode in textNodes)
        //        {
        //            textNode.SetAttribute(XmlTags.FontSizeTag, newFontSize.ToString());
        //        }
        //    }

        //    Action act = new Action(w.MasterEditor.Id, w.Id, w.GetType().Name, XmlTags.XmlDataInnerXml,
        //        oldXml, paragraphSetNode.InnerXml);
        //    //w.Build();//已更改，直接调用。
        //    mi.AddAction(act);
        //}

        //private static void ReplaceFontNameAttribute(string newFontName, ModifingItem<Action, ModifingInfo> mi, Widgets.Widget w)
        //{
        //    XmlNode paragraphSetNode = w.ParagraphSetNode;
        //    string oldXml = paragraphSetNode.InnerXml;

        //    //<ParagraphSet <Paragraph <Text 

        //    XmlNodeList paragraphNodes = paragraphSetNode.SelectNodes(XmlTags.ParagraphTag);
        //    foreach (XmlNode paragraphNode in paragraphNodes)
        //    {
        //        XmlNodeList textNodes = paragraphNode.SelectNodes(XmlTags.TextTag);
        //        foreach (XmlNode textNode in textNodes)
        //        {
        //            textNode.SetAttribute(XmlTags.FontNameTag, newFontName);
        //        }
        //    }

        //    Action act = new Action(w.MasterEditor.Id, w.Id, w.GetType().Name, XmlTags.XmlDataInnerXml,
        //        oldXml, paragraphSetNode.InnerXml);
        //    //w.Build();//已更改，直接调用。
        //    mi.AddAction(act);
        //}

        //private static void ReplaceFontWeightAttribute(FontWeight newFontWeight, ModifingItem<Action, ModifingInfo> mi, Widgets.Widget w)
        //{
        //    XmlNode paragraphSetNode = w.ParagraphSetNode;
        //    string oldXml = paragraphSetNode.InnerXml;

        //    //<ParagraphSet <Paragraph <Text 

        //    XmlNodeList paragraphNodes = paragraphSetNode.SelectNodes(XmlTags.ParagraphTag);
        //    foreach (XmlNode paragraphNode in paragraphNodes)
        //    {
        //        XmlNodeList textNodes = paragraphNode.SelectNodes(XmlTags.TextTag);
        //        foreach (XmlNode textNode in textNodes)
        //        {
        //            textNode.SetAttribute(XmlTags.FontWeightTag, newFontWeight.ToString());
        //        }
        //    }

        //    Action act = new Action(w.MasterEditor.Id, w.Id, w.GetType().Name, XmlTags.XmlDataInnerXml,
        //        oldXml, paragraphSetNode.InnerXml);
        //    //w.Build();//已更改，直接调用。
        //    mi.AddAction(act);
        //}
        #endregion
    }
}
